/*
 * Copyright (c) 2018 LingoChamp Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.liulishuo.okdownload.core.breakpoint;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.liulishuo.okdownload.core.Util;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.interwork.eventhandler.InnerEventUtils;

import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


public class RemitSyncExecutor {
    private static final String TAG = "RemitSyncExecutor";

    static final int WHAT_SYNC_BUNCH_ID = BreakpointStoreOnCache.FIRST_ID - 1;
    static final int WHAT_REMOVE_FREE_BUNCH_ID = BreakpointStoreOnCache.FIRST_ID - 2;
    static final int WHAT_REMOVE_FREE_ID = BreakpointStoreOnCache.FIRST_ID - 3;
    static final int WHAT_REMOVE_INFO = BreakpointStoreOnCache.FIRST_ID - 4;


    @NonNull
    private final EventHandler handler;

    @NonNull
    private final Set<Integer> freeToDBIdList;

    private
    @NonNull
    final RemitAgent agent;

    RemitSyncExecutor(@NonNull RemitAgent agent) {
        this.agent = agent;
        this.freeToDBIdList = new HashSet<>();
        EventRunner eventRunner = EventRunner.create(true);
        eventRunner.run();
        handler = new MyEventHandler(eventRunner, agent);
    }

    RemitSyncExecutor(@NonNull RemitAgent agent, @Nullable EventHandler handler,
                      @NonNull Set<Integer> freeToDBIdList) {
        this.agent = agent;
        this.handler = handler;
        this.freeToDBIdList = freeToDBIdList;
    }

    void shutdown() {
        this.handler.getEventRunner().stop();
    }

    boolean isFreeToDatabase(int id) {
        return freeToDBIdList.contains(id);
    }

    public void postSyncInfoDelay(int id, long delayMillis) {
        handler.sendEvent(id, delayMillis);
    }

    public void postSync(int id) {
        handler.sendEvent(id);
    }

    public void postSync(List<Integer> idList) {
        InnerEvent message = InnerEvent.get(WHAT_SYNC_BUNCH_ID);
        message.object = idList;
        handler.sendEvent(message);
    }

    public void postRemoveInfo(int id) {
        InnerEvent message = InnerEvent.get(WHAT_REMOVE_INFO);
        InnerEventUtils.setExInfo(message, id, 0);
        handler.sendEvent(message);
    }

    public void postRemoveFreeIds(List<Integer> idList) {
        final InnerEvent message = InnerEvent.get(WHAT_REMOVE_FREE_BUNCH_ID);
        message.object = idList;
        handler.sendEvent(message);
    }

    public void postRemoveFreeId(int id) {
        final InnerEvent message = InnerEvent.get(WHAT_REMOVE_FREE_ID);
        InnerEventUtils.setExInfo(message, id, 0);
        handler.sendEvent(message);
    }

    void removePostWithId(int id) {
        handler.removeEvent(id);
    }

    void removePostWithIds(int[] ids) {
        for (int id : ids) {
            handler.removeEvent(id);
        }
    }

    class MyEventHandler extends EventHandler {

        private RemitAgent mAgent;

        public MyEventHandler(EventRunner runner, RemitAgent agent) throws IllegalArgumentException {
            super(runner);
            mAgent = agent;
        }

        @Override
        protected void processEvent(InnerEvent msg) {
            super.processEvent(msg);
            List<Integer> idList;
            int id;
            switch (msg.eventId) {
                case WHAT_REMOVE_INFO:
                    id = InnerEventUtils.getArg1(msg);
                    freeToDBIdList.remove(id);
                    mAgent.removeInfo(id);
                    Util.d(TAG, "remove info " + id);
                    break;
                case WHAT_REMOVE_FREE_BUNCH_ID:
                    // remove bunch free-ids
                    idList =  ObjCastUtils.objToList(msg.object,Integer.class);
                    freeToDBIdList.removeAll(idList);
                    Util.d(TAG, "remove free bunch ids " + idList);
                    break;
                case WHAT_REMOVE_FREE_ID:
                    // remove free-id
                    id = InnerEventUtils.getArg1(msg);
                    freeToDBIdList.remove(id);
                    Util.d(TAG, "remove free bunch id " + id);
                    break;
                case WHAT_SYNC_BUNCH_ID:
                    // sync bunch id
                    idList=   ObjCastUtils.objToList(msg.object,Integer.class);
                    try {
                        mAgent.syncCacheToDB(idList);
                        freeToDBIdList.addAll(idList);
                        Util.d(TAG, "sync bunch info with ids: " + idList);
                    } catch (IOException e) {
                        Util.w(TAG, "sync info to db failed for ids: " + idList);
                    }
                    break;
                default:
                    // sync id
                    id = msg.eventId;
                    try {
                        mAgent.syncCacheToDB(id);
                        freeToDBIdList.add(id);
                        Util.d(TAG, "sync info with id: " + id);
                    } catch (IOException e) {
                        Util.w(TAG, "sync cache to db failed for id: " + id);
                    }
                    break;
            }
        }
    }

    interface RemitAgent {
        void syncCacheToDB(List<Integer> idList) throws IOException;

        void syncCacheToDB(int id) throws IOException;

        void removeInfo(int id);
    }
}
